package vsqlbuilder.gui;

import static vsqlbuilder.Utils.MINIFONT;

import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JTextField;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;

import vsqlbuilder.Utils.typeofConnector;
import vsqlbuilder.Utils.typeofRestriction;
import vsqlbuilder.logic.sql.Query;
import vsqlbuilder.logic.sql.QueryRestriction;



public class TabRestrictions extends JPanel {
	static final long serialVersionUID = 0L; // TODO [low]: temporary
	// fix,should be change to
	// correct one
	private static final String[] restrictionsStrings ={"=","!=","<",">","<=",">=","BETWEEN","NOT BETWEEN","LIKE","NOT LIKE", "ILIKE", "NOT ILIKE","IS NULL", "IS NOT NULL","IN","NOT IN"};
	private static final String[] logicStrings ={"AND","OR"};
	private List<RestrictionRow> listRows;
	// private QueryRestrictionsList listRestrictions;
	private GridBagConstraints layoutConstraints;
	private GridBagLayout l;
	private Query query;
	private JPopupMenu mainMenu;
	public JButton mainButton;
	private JLabel mainLabel;
	private static boolean showMainMenu;
	private int usedIndex;
	private int usedSubIndex;
	private MainController controller;
	private ColumnsTreeDialog SelTreeColsDialog;


	
	

	public TabRestrictions(MainController controller) {
		this.controller=controller;
		this.query = controller.Model.QueryStatment; 
		
		this.usedIndex = 0; // first index & subinddex to use in buttons of
		// restrictions
		this.usedSubIndex = 0; // but be careful they aren't zero based they
		// are based on 1
		listRows = new ArrayList<RestrictionRow>();
		// Layout Configuration
		l = new GridBagLayout();
		layoutConstraints = new GridBagConstraints();
		layoutConstraints.insets = new Insets(1, 1, 1, 1);
		layoutConstraints.anchor = GridBagConstraints.NORTH;
		layoutConstraints.fill = GridBagConstraints.NORTH;
		this.setLayout(l);
		this.CreateMainButton();
	}

	public void CreateMainButton(){
		//Create Main Button
		mainButton = createButton("Add Restriction");
		addComponent(mainButton, 0, 0, 1, 1);
		mainLabel = new JLabel("Following restrictions are accomplished:");
		addComponent(mainLabel, 0, 1, 6, 1);
		// Main Button Popup Menu event
		showMainMenu = false;
		ActionListener al = new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				
				if (!showMainMenu) {
					mainMenu.show(mainButton, 20, 20);
					showMainMenu = true;
				} else {
					mainMenu.setVisible(false);
					showMainMenu = false;
				}
				// Action of Main Button Add Conditions to query AT THE END
				// [from main button]
				if (e.getActionCommand().equalsIgnoreCase(
						"Add Condition to Query")) {
					TabRestrictions.this.usedIndex++;
					TabRestrictions.this.usedSubIndex = 0;
					RestrictionRow dataRow = createRow(
							TabRestrictions.this.listRows.size(), false,
							TabRestrictions.this.usedIndex,
							TabRestrictions.this.usedSubIndex);
					TabRestrictions.this.listRows.add(dataRow);
					TabRestrictions.this.revalidate();
				}
				// Action of Main Button Add Composite Condition to Query END
				// [from main button]
				if (e.getActionCommand().equalsIgnoreCase(
						"Add Composite Condition to Query")) {
					if (TabRestrictions.this.usedSubIndex == 0) {
						TabRestrictions.this.usedIndex++;
					}
					TabRestrictions.this.usedSubIndex++;
					RestrictionRow dataRow = createRow(
							TabRestrictions.this.listRows.size(), true,
							TabRestrictions.this.usedIndex,
							TabRestrictions.this.usedSubIndex);
					TabRestrictions.this.listRows.add(dataRow);
					TabRestrictions.this.revalidate();

				}
				// Action of Main Button Remove all conditions [in Jpanel]
				if (e.getActionCommand().equalsIgnoreCase(
				"Remove all Conditions")) {
					TabRestrictions.this.clearTabRestrictions();
				}
			}
		};

		// Main Popup Menu Configuration
		JMenuItem menuItem;
		mainMenu = new JPopupMenu();
		menuItem = new JMenuItem("Add Condition to Query");
		menuItem.setHorizontalTextPosition(JMenuItem.RIGHT);
		menuItem.addActionListener(al);
		mainMenu.add(menuItem);
		menuItem = new JMenuItem("Add Composite Condition to Query");
		menuItem.setHorizontalTextPosition(JMenuItem.RIGHT);
		menuItem.addActionListener(al);
		mainMenu.add(menuItem);
		menuItem = new JMenuItem("Remove all Conditions");
		menuItem.setHorizontalTextPosition(JMenuItem.RIGHT);
		menuItem.addActionListener(al);
		mainMenu.add(menuItem);

		// Add Popup Action to Main Menu
		mainButton.addActionListener(al);
		mainButton.setEnabled(false);
	}
	
	
	public void clearTabRestrictions(){

		for(RestrictionRow r: listRows){
			this.remove(r.column);
			this.remove(r.index);
			this.remove(r.subIndex);
			this.remove(r.kindOfRestriction);
			this.remove(r.value1);
			this.remove(r.value2);
			this.remove(r.connector);
			this.remove(r.logicConnection);
		}
		this.listRows.clear();
		this.query.getRestrictionsList().clear();
		this.updateUI();
		this.usedIndex = 0; // first index & subinddex to use in buttons of
		// restrictions
		this.usedSubIndex = 0; // but be careful they aren't zero based they
		// are based on 1
	}
	
	// Row is zero based
	public RestrictionRow createRow(int layoutRow, boolean composite,
			int buttonIndex, int buttonSubIndex) {
		QueryRestriction queryRestriction = this.query
				.AddRestrictionToQuery(layoutRow); //layout row is the same as list size
		layoutRow++; // correct row position in layout because is 1 based (0
		// is not used in this function)
		
		final RestrictionRow rr = new RestrictionRow(queryRestriction,this);
		//TODO [low]: remove all not needed here
		
		//Main Button of A ROW
		rr.setIndex(Integer.toString(buttonIndex));

		//Sub Button of A ROW
		if(this.usedSubIndex>0){  //then this is a row of a composite condition
			queryRestriction.setGroup(this.usedIndex);
		}
		rr.setSubIndex(Integer.toString(buttonIndex) + "."
				+ Integer.toString(buttonSubIndex));
		
		//Select Schema Table Column  
		rr.column.setForeground(Color.RED);
		rr.setColumn("Click to select Column...");

		MouseListener colMl= new MouseListener(){
			public void mouseClicked(MouseEvent e){
				//Initialize Selection Tree of Columns [Because a bug getting top parent frame is not initialized on class constructor]
				if(SelTreeColsDialog==null){
					SelTreeColsDialog = new ColumnsTreeDialog((JFrame)TabRestrictions.this.getTopLevelAncestor(),TabRestrictions.this.controller);
				}
				int xCorrected=(int)rr.column.getLocationOnScreen().getX()+e.getX()+1;
				int yCorrected= (int)rr.column.getLocationOnScreen().getY()+e.getY()+1;
				SelTreeColsDialog.setVisible(true,xCorrected,yCorrected,rr.column);
				rr.column.setForeground(Color.BLACK);
				rr.restriction.setExpresion(rr.column.getText());
			}
			public void mouseReleased(MouseEvent e){}
			public void mouseExited(MouseEvent e){}
			public void mouseEntered(MouseEvent e){}
			public void mousePressed(MouseEvent e){}
		};
		rr.column.addMouseListener(colMl);
		
		//Is a composite Row
		rr.setComposite(composite);
		
		//Add Components to the Application Layout
		addComponent(rr.index, layoutRow, 0, 1, 1);
		addComponent(rr.subIndex, layoutRow, 1, 1, 1);
		addComponent(rr.column, layoutRow, 2, 1, 1);
		addComponent(rr.kindOfRestriction, layoutRow, 3, 1, 1);
		addComponent(rr.value1, layoutRow, 4, 1, 1);
		addComponent(rr.connector, layoutRow, 5, 1, 1);
		addComponent(rr.value2, layoutRow, 6, 1, 1);
		addComponent(rr.logicConnection,layoutRow, 7, 1, 1);
		return rr;
	}

	public static JButton createButton(String text) {
		JButton button = new JButton(text);
		button.setFont(MINIFONT);
		Dimension preferredSize = button.getPreferredSize();
		preferredSize.width = 80;
		preferredSize.height = 20;
		button.setMinimumSize(preferredSize);
		button.setPreferredSize(preferredSize);
		button.setMaximumSize(preferredSize);
		return button;
	}

	private void addComponent(Component component, int row, int column,
			int width, int height) {
		// set gridx and gridy
		layoutConstraints.gridx = column;
		layoutConstraints.gridy = row;
		// set gridwidth and gridheight
		layoutConstraints.gridwidth = width;
		layoutConstraints.gridheight = height;
		// set restrictions and add component
		l.setConstraints(component, layoutConstraints);
		this.add(component);
	}

	//this nested class only manage components on each row of a restriction & link with a query restriction, nothing more. 
	private class RestrictionRow {
		
		public final JButton index, subIndex;
		public final JLabel column, connector;
		public final JComboBox kindOfRestriction;
		public final JTextField value1, value2;
		public final QueryRestriction restriction;
		public final JComboBox logicConnection;
		private final JPopupMenu SubMenu;
		private boolean showSubMenu;
		private TabRestrictions ownerPanel;

		public RestrictionRow(QueryRestriction qr, TabRestrictions owner) {
			restriction = qr;
			ownerPanel = owner;
			
			showSubMenu=false;
			//Main button (NOT Composite Restriction)
			index =createButton("");
			ActionListener alIndex = new ActionListener(){
				public void actionPerformed(ActionEvent e){
					if(!showSubMenu){
						showSubMenu=true;
						RestrictionRow.this.SubMenu.show(index,20,20);
					}else{
						showSubMenu=false;
						RestrictionRow.this.SubMenu.setVisible(false);
					}
				}
			};
			index.addActionListener(alIndex);

			//Subgroup button (Composite Restriction)
			subIndex=createButton("");
			ActionListener alSubIndex = new ActionListener(){
				public void actionPerformed(ActionEvent e){
					if(!showSubMenu){
						showSubMenu=true;
						RestrictionRow.this.SubMenu.show(subIndex,20,20);
					}else{
						showSubMenu=false;
						RestrictionRow.this.SubMenu.setVisible(false);
					}
				}
			};
			subIndex.addActionListener(alSubIndex);
			
			// Main Popup Menu Configuration
			JMenuItem menuItem;
			SubMenu = new JPopupMenu();
			menuItem = new JMenuItem("Remove Restriction");
			menuItem.setHorizontalTextPosition(JMenuItem.RIGHT);
			ActionListener alItem = new ActionListener(){
				public void actionPerformed(ActionEvent e){
					if (e.getActionCommand().equalsIgnoreCase(
					"Remove Restriction")) {
						ownerPanel.remove(RestrictionRow.this.column);
						ownerPanel.remove(RestrictionRow.this.index);
						ownerPanel.remove(RestrictionRow.this.subIndex);
						ownerPanel.remove(RestrictionRow.this.kindOfRestriction);
						ownerPanel.remove(RestrictionRow.this.value1);
						ownerPanel.remove(RestrictionRow.this.value2);
						ownerPanel.remove(RestrictionRow.this.connector);
						ownerPanel.remove(RestrictionRow.this.logicConnection);
						ownerPanel.query.removeRestrictionFromQuery(RestrictionRow.this.restriction);
						ownerPanel.listRows.remove(this);
						ownerPanel.updateUI();
						//TODO[medium]: Fix the index & subindex button text because change after remove a restricion composite or not.
					}
				}
			};
			menuItem.addActionListener(alItem);
			SubMenu.add(menuItem);

			
			
			
			
			
			//Selected Column of table
			column = new JLabel();
			
			//Connector of restriction
			restriction.setTypeConnector(typeofConnector.AND);
			logicConnection= new JComboBox(logicStrings);
			logicConnection.setSelectedIndex(0);
			logicConnection.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					String stringConnector= (String) logicConnection.getItemAt(logicConnection.getSelectedIndex());
					if(stringConnector.equals("AND")){
						restriction.setTypeConnector(typeofConnector.AND);
					}else if(stringConnector.equals("OR")){
						restriction.setTypeConnector(typeofConnector.OR);
					}

				}
			});
			
			//ComboBox of kind of restriction selected
			restriction.setTypeRestriction(typeofRestriction.EQUAL);
			kindOfRestriction = new JComboBox(restrictionsStrings);
			kindOfRestriction.setSelectedIndex(0);
			kindOfRestriction.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					String stringRestriction= (String) kindOfRestriction.getItemAt(kindOfRestriction.getSelectedIndex());
					typeofRestriction typeR=typeofRestriction.EQUAL;
					//TODO [low]: research if a switch can be use without side effects (or at least move to queryrestricion class), working like .equals (compare string content) and not like ==  (compare objects) when comparing strings
					if(stringRestriction.equals("=")){
						typeR=typeofRestriction.EQUAL;
					}else if(stringRestriction.equals("!=")){
						typeR=typeofRestriction.NOT_EQUAL;
					}else if(stringRestriction.equals("<")){
						typeR=typeofRestriction.LESS;
					}else if(stringRestriction.equals(">")){
						typeR=typeofRestriction.MORE;
					}else if(stringRestriction.equals("<=")){
						typeR=typeofRestriction.LESS_EQUAL;
					}else if(stringRestriction.equals(">=")){
						typeR=typeofRestriction.MORE_EQUAL;
					}else if(stringRestriction.equals("BETWEEN")){
						typeR=typeofRestriction.BETWEEN;
					}else if(stringRestriction.equals("NOT BETWEEN")){
						typeR=typeofRestriction.NOT_BETWEEN;
					}else if(stringRestriction.equals("LIKE")){
						typeR=typeofRestriction.LIKE;
					}else if(stringRestriction.equals("NOT LIKE")){
						typeR=typeofRestriction.NOT_LIKE;
					}else if(stringRestriction.equals("ILIKE")){
						typeR=typeofRestriction.ILIKE;
					}else if(stringRestriction.equals("NOT ILIKE")){
						typeR=typeofRestriction.NOT_ILIKE;
					}else if(stringRestriction.equals("IS NULL")){
						typeR=typeofRestriction.IS_NULL;
					}else if(stringRestriction.equals("IS NOT NULL")){
						typeR=typeofRestriction.IS_NOT_NULL;
					}else if(stringRestriction.equals("IN")){
						typeR=typeofRestriction.IN;
					}else if(stringRestriction.equals("NOT IN")){
						typeR=typeofRestriction.NOT_IN;
					}
					restriction.setTypeRestriction(typeR);
					
					//Now check which components should be visible
					if(stringRestriction.equals("NOT BETWEEN") || stringRestriction.equals("BETWEEN")){
						connector.setText("AND");
						connector.setVisible(true);
						value2.setVisible(true);
					}else{
						connector.setText("");
						connector.setVisible(false);
						value2.setVisible(false);						
					}
				}
			});
			connector = new JLabel();
			//Text Field of first value
			value1 = new JTextField(20);
			DocumentListener v1dl = new DocumentListener(){
				public void insertUpdate(DocumentEvent de){
					restriction.setValue1(value1.getText());
				}
				public void changedUpdate(DocumentEvent de){
					restriction.setValue1(value1.getText());
				}
				public void removeUpdate(DocumentEvent de){
					restriction.setValue1(value1.getText());
				}
			};
			value1.getDocument().addDocumentListener(v1dl);
			//Text Field of second value
			value2 = new JTextField(20);
			DocumentListener v2dl = new DocumentListener(){
				public void insertUpdate(DocumentEvent de){
					restriction.setValue2(value2.getText());
				}
				public void changedUpdate(DocumentEvent de){
					restriction.setValue2(value2.getText());
				}
				public void removeUpdate(DocumentEvent de){
					restriction.setValue2(value2.getText());
				}
			};
			value2.getDocument().addDocumentListener(v2dl);
			//Set default visibility of last two components
			connector.setVisible(false);
			value2.setVisible(false);	
		}

		public void setIndex(String s) {
			this.index.setText(s);
		}

		public void setSubIndex(String s) {
			this.subIndex.setText(s);
		}

		public void setColumn(String c) {
			this.column.setText(c);
		}
		
		public void setConnector(String c) {
			this.connector.setText(c);
		}

		public void setComposite(boolean composite) {
			if (composite) {
				index.setVisible(false);
				subIndex.setVisible(true);
			} else {
				index.setVisible(true);
				subIndex.setVisible(false);
			}
		}

		public QueryRestriction getRestriction(){
			return this.restriction;
		}
	}
}